为什么Java中的密码优先使用 char[] 而不是 String?

  1. java中的字符串是不可变的。因此,无论何时创建字符串,它都将保留在内存中,直到被垃圾收集为止。因此,任何访问内存的人都可以读取字符串的值。 如果修改了字符串的值,那么它最终将创建一个新字符串。因此,原始值和修改后的值都保留在内存中,直到垃圾回收为止。

  2. 使用字符数组,一旦达到密码的目的,就可以修改或删除数组的内容。数组的原始内容在修改后甚至在垃圾收集开始之前都不会在内存中找到。出于安全考虑,最好将密码存储为字符数组

  3. 使用String总是有在日志文件或控制台中打印纯文本的风险,但是如果使用数组,则不会打印数组的内容,而是打印其内存位置。虽然这不是一个真正的原因,但仍然有意义。注意要拼接字符串才打印地址信息。

     String pwd = "123456";
     // 使用 java 推荐的方式
     JPasswordField jPasswordField = new JPasswordField(pwd);
     char[] password1 = jPasswordField.getPassword();
     System.out.println(password1); //123456
    
    // 普通方式
    char[] chars = pwd.toCharArray();
    System.out.println(chars); //123456
    
    System.out.println("Array:" + chars); //Array:[C@7daf6ecc
    

推荐方式:

使用 char[]进行保存比较,使用完清空内存数据。

char[] passw = request.getPassword().toCharArray()
if (comparePasswords(dbPassword, passw) {
 allowUser = true;
 cleanPassword(passw);
 cleanPassword(dbPassword);
 passw=null;
}

private static void cleanPassword (char[] pass) {
 for (char ch: pass) {
  ch = '0';
 }
}

大多数情况都是保存为字符串的,可以考虑严格的加密方式,如存储在数据库的信息都是散列函数加密过的信息, 不需要明文,只进行验证处理 。但是 如果获取的字符串,变量用这种方式String s=new String(request.getParameter("XXX"))的方式,应该不会直接扔到常量池,而是直接映射到堆内存中,我觉得 或许可以减少这个明文在内存中存储的时间

上次更新时间: 2024/5/7 05:59:02